package wechat

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	uuid "github.com/lithammer/shortuuid/v4"
	"go-admin/server/internal/domain"
	"net/http"
	"net/url"
)

const authURLPattern = "https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_login&state=%s#wechat_redire"

var redirectURI = url.PathEscape("https://meoying.com/oauth2/wechat/callback")

type Service interface {
	AuthURl(ctx context.Context) (string, error)
	VerifCode(ctx context.Context, code, state string) (domain.WeChatInfo, error)
}

type service struct {
	appId     string
	appSecret string
	client    *http.Client
}

func NewService(appId, appSecret string) Service {
	return &service{
		appId:     appId,
		appSecret: appSecret,
		client:    http.DefaultClient,
	}
}

func (s *service) AuthURl(ctx context.Context) (string, error) {
	state := uuid.New()
	return fmt.Sprintf(authURLPattern, s.appId, redirectURI, state), nil
}
func (s *service) VerifCode(ctx context.Context, code, state string) (domain.WeChatInfo, error) {
	const baseURL = "https://api.weixin.qq.com/sns/oauth2/access_token"
	queryParams := url.Values{}
	queryParams.Set("appid", s.appId)
	queryParams.Set("secret", s.appSecret)
	queryParams.Set("code", code)
	queryParams.Set("grant_type", "authorization_code")
	accessTokenURL := baseURL + "?" + queryParams.Encode()

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, accessTokenURL, nil)
	if err != nil {
		return domain.WeChatInfo{}, err
	}
	do, err := s.client.Do(req)
	if err != nil {
		return domain.WeChatInfo{}, err
	}
	decoder := json.NewDecoder(do.Body)
	var res Result
	err = decoder.Decode(&res)
	if err != nil {
		return domain.WeChatInfo{}, err
	}
	if res.ErrCode != 0 {
		return domain.WeChatInfo{}, errors.New("微信返回错误信息")
	}
	return domain.WeChatInfo{
		OpenID:  res.OpenId,
		UnionID: res.UnionId,
	}, nil
}

type Result struct {
	ErrCode int64  `json:"errcode"`
	ErrMsg  string `json:"errMsg"`

	Scope string `json:"scope"`

	AccessToken  string `json:"access_token"`
	ExpiresIn    int64  `json:"expires_in"`
	RefreshToken string `json:"refresh_token"`

	OpenId  string `json:"openid"`
	UnionId string `json:"unionid"`
}
